package BloomfilterTwo;

import com.google.common.base.Charsets;
import com.google.common.hash.Funnels;
import com.google.common.hash.Hashing;
import com.google.common.primitives.Longs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;

@Component
public class RedisBloomFilter {
    public final static String Bloomfilter = "Bloomfilter";
    private int numApproxElements;  // 预计元素个数
    private double fpp;  // 误判率
    private int numHashFunctions;  // 哈希函数个数
    private int bitmapLength;  // 位图长度


    @Autowired
    private JedisPool jedisPool;


    public RedisBloomFilter init(int numApproxElements, double fpp) {
        this.numApproxElements = numApproxElements;
        this.fpp = fpp;
        // 计算哈希函数个数和位图长度
        this.bitmapLength = (int)(-numApproxElements * Math.log(fpp) / (Math.pow(Math.log(2), 2)));  // 位数组长度
        this.numHashFunctions = Math.max(1, (int)Math.round((double)bitmapLength/numApproxElements*Math.log(2)));  // 哈希函数个数
        return this;
    }

    private long[] getBitIndics(String element){
        long[] indices = new long[numHashFunctions];
        byte[] bytes = Hashing.murmur3_128().hashObject(element, Funnels.stringFunnel(Charsets.UTF_8)).asBytes();
        long hash1 = Longs.fromBytes(bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]);
        long hash2 = Longs.fromBytes(bytes[15], bytes[14], bytes[13], bytes[12], bytes[11], bytes[10], bytes[9], bytes[8]);

        long combinedHash =hash1;
        for (int i=0; i<numHashFunctions; i++){
            indices[i] = (combinedHash&Long.MAX_VALUE) % bitmapLength;
            combinedHash = hash2 + combinedHash;
        }
        System.out.println(element + "数组下标");
        for (long index : indices) {
            System.out.print(index + "  ,  ");
        }
        System.out.println("  ");
        return indices;
    }


    public  void insert(String key, String element, int expireSec){
        if ( key==null || element == null ) {
            throw new RuntimeException("键值都不能为空");
        }
        String actualKey = Bloomfilter.concat(key);

        try( Jedis jedis = jedisPool.getResource() ) {
            try(Pipeline pipeline = jedis.pipelined()) {
                for (long index : getBitIndics(element)) {
                    pipeline.setbit(actualKey, index, true);
                }
                pipeline.syncAndReturnAll() ;
            }catch (Exception e){
                e.printStackTrace();
            }
            jedis.expire(actualKey, expireSec);
        }catch (Exception e){
            e.printStackTrace();
        }
    }




}
